package com.mm.redis;

import com.alibaba.fastjson.JSON;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * redis服务
 */
@Service
public class RedisService {

	@Resource
	JedisPool jedisPool;

	/**
	 * 从redis连接池获取redis实例
	 */
	public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			// 对key增加前缀，即可用于分类，也避免key重复
			String realKey = prefix.getPrefix() + key;
			String str = jedis.get(realKey);
			T t = stringToBean(str, clazz);
			return t;
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 根据key获取value值
	 */
	public JSONObject getValue(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			String string = jedis.get(key);
			JSONObject object = JSONObject.fromObject(string);
			return object;
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 存储对象
	 */
	public <T> Boolean set(KeyPrefix prefix, String key, T value) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			String str = beanToString(value);
			if (str == null || str.length() <= 0) {
				return false;
			}
			String realKey = prefix.getPrefix() + key;
			int seconds = prefix.expireSeconds();// 获取过期时间
			if (seconds <= 0) {
				jedis.set(realKey, str);
			} else {
				jedis.setex(realKey, seconds, str);
			}
			return true;
		} finally {
			returnToPool(jedis);
		}

	}

	/**
	 * 删除
	 */
	public boolean delete(KeyPrefix prefix, String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			// 生成真正的key
			String realKey = prefix.getPrefix() + key;
			long ret = jedis.del(realKey);
			return ret > 0;
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 删除key
	 *
	 * @param key
	 * @return
	 */
	public boolean deleteKey(String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			long ret = jedis.del(key);
			return ret > 0;
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 判断key是否存在
	 */
	public <T> boolean exists(KeyPrefix prefix, String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			// 生成真正的key
			String realKey = prefix.getPrefix() + key;
			return jedis.exists(realKey);
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 查询所有的key
	 */
	public Jedis getAllKey() {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			return jedis;
		} finally {
			returnToPool(jedis);
		}

	}

	/**
	 * 增加值 Redis Incr 命令将 key 中储存的数字值增一。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR
	 * 操作
	 */
	public <T> Long incr(KeyPrefix prefix, String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			// 生成真正的key
			String realKey = prefix.getPrefix() + key;
			return jedis.incr(realKey);
		} finally {
			returnToPool(jedis);
		}
	}

	/**
	 * 减少值
	 */
	public <T> Long decr(KeyPrefix prefix, String key) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			// 生成真正的key
			String realKey = prefix.getPrefix() + key;
			return jedis.decr(realKey);
		} finally {
			returnToPool(jedis);
		}
	}

	public static <T> String beanToString(T value) {
		if (value == null) {
			return null;
		}
		Class<?> clazz = value.getClass();
		if (clazz == int.class || clazz == Integer.class) {
			return String.valueOf(value);
		} else if (clazz == long.class || clazz == Long.class) {
			return String.valueOf(value);
		} else if (clazz == String.class) {
			return (String) value;
		} else {
			return JSON.toJSONString(value);
		}

	}

	@SuppressWarnings("unchecked")
	public static <T> T stringToBean(String str, Class<T> clazz) {
		if (str == null || str.length() <= 0 || clazz == null) {
			return null;
		}
		if (clazz == int.class || clazz == Integer.class) {
			return (T) Integer.valueOf(str);
		} else if (clazz == long.class || clazz == Long.class) {
			return (T) Long.valueOf(str);
		} else if (clazz == String.class) {
			return (T) str;
		} else {
			return JSON.toJavaObject(JSON.parseObject(str), clazz);
		}
	}

	/**
	 * 返回删除redis
	 * 
	 * @param <T>         实体对象
	 * @param prefixKey   redisKey的前缀
	 * @param clazz       实体对象
	 * @param UniqueRedis redis唯一标识值
	 * @param UniqueDB    数据库唯一标识值
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> Boolean deleteKeys(String prefixKey, T clazz, String UniqueRedis, String UniqueDB) {
		try {
			// 查询缓存中关于的key值
			Set<String> keys = getAllKey().keys(prefixKey + "*");
			Object object = null;
			// 遍历所有的key值
			for (String key : keys) {
				// 获得key值对应的value值
				JSONObject value = getValue(key);
				object = value.get("list");
				Iterator<T> it = ((List<T>) object).iterator();
				// 遍历value中的数组
				while (it.hasNext()) {
					// 遍历后的结果转换为json
					JSONObject object2 = JSONObject.fromObject(it.next());
					Object object3 = object2.get(UniqueRedis);
					// 比较缓存中的值和数据库中的值，如果有相同，如果相同，那么删除缓存中的key值
					if (object3.toString().equals(UniqueDB)) {
						deleteKey(key);
					} else {
						return false;
					}
				}
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 删除关联数据的key值
	 * 
	 * @param <T>
	 * @param prefixKey     redisKey的前缀
	 * @param clazz         实体对象
	 * @param UniqueRedis01 redis唯一标识值
	 * @param UniqueRedis02 list中集合的对象key
	 * @param UniqueDB      数据可以的唯一值
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> Boolean deleteKeysAssociated(String prefixKey, T clazz, String UniqueRedis01, String UniqueRedis02,
			String UniqueDB) {
		try {
			// 查询缓存中关于的key值
			Set<String> keys = getAllKey().keys(prefixKey + "*");
			Object object = null;
			// 遍历所有的key值
			for (String key : keys) {
				// 获得key值对应的value值
				JSONObject value = getValue(key);
				object = value.get("list");
				Iterator<T> it = ((List<T>) object).iterator();
				// 遍历value中的数组
				while (it.hasNext()) {
					// 遍历后的结果转换为json
					JSONObject object2 = JSONObject.fromObject(it.next());
					// 获取关联的对象
					Object object3 = object2.get(UniqueRedis01);
					JSONObject fromObject = JSONObject.fromObject(object3);
					for (int i = 0; i < fromObject.size(); i++) {
						// 获取关联里面的唯一值
						Object object4 = fromObject.get(UniqueRedis02);
						// 比较缓存中的值和数据库中的值，如果有相同，如果相同，那么删除缓存中的key值
						if (object4.toString().equals(UniqueDB)) {
							deleteKey(key);
						} else {
							return false;
						}

					}

				}
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 删除所有的rediskey
	 * 
	 * @param pageById redis键ID
	 * @param pageList redis键列表
	 * @return
	 */
	public boolean redisAllKey(String pageById, String pageList) {

		try {
			// 处理缓存
			Set<String> keys = getAllKey().keys(pageList + "*");
			for (String key : keys) {
				deleteKey(key);
			}
			Set<String> keys2 = getAllKey().keys(pageById + "*");
			for (String key : keys2) {
				deleteKey(key);
			}
			return true;
		} catch (Exception e) {
			return false;
		}

	}

	private void returnToPool(Jedis jedis) {
		if (jedis != null) {
			jedis.close();// 不是关闭，只是返回连接池
		}
	}

}
